package com.yycx.module.system.provider.service.impl;

import com.yycx.common.constants.CommonConstants;
import com.yycx.common.mybatis.base.service.impl.BaseServiceImpl;
import com.yycx.common.base.entity.EntityMap;
import com.yycx.common.mybatis.model.ResultBody;
import com.yycx.common.mybatis.query.CriteriaQuery;
import com.yycx.common.base.utils.FlymeUtils;
import com.yycx.common.mybatis.query.CriteriaUpdate;
import com.yycx.common.utils.RedisUtils;
import com.yycx.module.system.client.entity.SysArea;
import com.yycx.module.system.provider.mapper.SysAreaMapper;
import com.yycx.module.system.provider.service.SysAreaService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * 区域表 服务实现类
 *
 * @author flyme
 * @date 2019-06-11
 */
@Service
@Transactional(rollbackFor = Exception.class)
@Slf4j
public class SysAreaServiceImpl extends BaseServiceImpl<SysAreaMapper, SysArea> implements SysAreaService {
    @Autowired
    private RedisUtils redisUtils;

    @Override
    public ResultBody selectByLevel(Integer level) {
        CriteriaQuery<SysArea> cq = new CriteriaQuery(SysArea.class);
        cq.select("areaId as value", "areaName as label", "parentId", "firstLetter", "fullLetter", "adCode", "location","shortName","letter");
        cq.eq(true, "areaLevel", level);
        cq.eq(true, "enabled", CommonConstants.ENABLED);
        cq.orderByAsc("firstLetter");
        return ResultBody.ok(selectEntityMap(cq));
    }

    @Override
    public List<EntityMap> selectHotList() {
        CriteriaQuery<SysArea> cq = new CriteriaQuery(SysArea.class);
        cq.select("areaId as value", "areaName as label", "parentId", "adCode", "location","shortName","letter");
        cq.eq(true, "hot", 1);
        cq.eq(true, "enabled", CommonConstants.ENABLED);
        cq.orderByAsc("firstLetter");
        return selectEntityMap(cq);
    }


    @Override
    public ResultBody selectByLevel(Integer level, Long areaId) {
        CriteriaQuery<SysArea> cq = new CriteriaQuery(SysArea.class);
        cq.select("areaId as value", "areaName as label", "parentId", "adCode","shortName","letter").eq(true, "areaLevel", level).eq("parentId", areaId);
        cq.eq(true, "enabled", CommonConstants.ENABLED);
        cq.orderByAsc("firstLetter");
        return baseList(cq);
    }

    @Override
    public void initArea(Boolean init) {
        List<Object> list = redisUtils.getList(CommonConstants.REDIS_KEY_ALLAREA);
        if (FlymeUtils.isEmpty(list) || init) {
            List<Map<Object, Object>> list1 = (List<Map<Object, Object>>) selectListByLevel(1).getData();
            List<Map<Object, Object>> list2 = (List<Map<Object, Object>>) selectListByLevel(2).getData();
            List<Map<Object, Object>> list3 = (List<Map<Object, Object>>) selectListByLevel(3).getData();
            List<Map<Object, Object>> result = new ArrayList<>();
            if (FlymeUtils.isNotEmpty(list1)) {
                for (Map<Object, Object> first : list1) {
                    List<Object> child = getCity(first, list2, list3);
                    first.put("child", child);
                    result.add(first);

                }
            }
            redisUtils.del(CommonConstants.REDIS_KEY_ALLAREA);
            redisUtils.setList(CommonConstants.REDIS_KEY_ALLAREA, result);
            log.info("区域数据已缓存...");
        }
    }

    private ResultBody selectListByLevel(Integer level) {
        CriteriaQuery<SysArea> cq = new CriteriaQuery(SysArea.class);
        cq.select("areaId", "areaName", "parentId", "areaLevel", "adCode", "location","hot","enabled","shortName","letter");
        cq.eq(true, "areaLevel", level);
        cq.orderByAsc("firstLetter");
        return ResultBody.ok(listMaps(cq));
    }


    @Override
    @Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
    public List<EntityMap> listByParentId(Long parentId) {
        CriteriaQuery<SysArea> cq = new CriteriaQuery(SysArea.class);
        cq.select(SysArea.class, "areaId", "areaName","parentId");
        cq.eq(true, "enabled", CommonConstants.ENABLED);
        cq.eq("parentId", parentId);
        return selectEntityMap(cq);
    }

    @Override
    public ResultBody getAllArea() {
        List<Object> list = redisUtils.getList(CommonConstants.REDIS_KEY_ALLAREA);
        return ResultBody.ok(list);
    }

    public List<Object> getCity(Map<Object, Object> first, List<Map<Object, Object>> list2, List<Map<Object, Object>> list3) {
        List<Object> result = new ArrayList<>();
        String firstId = first.get("areaId").toString();
        if (FlymeUtils.isNotEmpty(list2)) {
            for (Map<Object, Object> second : list2) {
                String parentId = second.get("parentId").toString();
                List<Object> areaList = getArea(second, list3);
                second.put("child", areaList);
                if (firstId.equals(parentId)) {
                    result.add(second);
                }
            }
        }
        return result;
    }


    public List<Object> getArea(Map<Object, Object> second, List<Map<Object, Object>> list3) {
        List<Object> result = new ArrayList<>();
        String secondId = second.get("areaId").toString();
        if (FlymeUtils.isNotEmpty(list3)) {
            for (Map<Object, Object> three : list3) {
                String parentId = three.get("parentId").toString();
                if (secondId.equals(parentId)) {
                    result.add(three);
                }
            }
        }
        return result;
    }


    /**
     * 递归构建
     *
     * @param list
     * @param parentId
     * @return
     */
    private static List<EntityMap> buildTree(List<EntityMap> list, Long parentId) {
        List<EntityMap> result = new ArrayList();
        list.forEach(category -> {
            Long categoryId = category.getLong("areaId");
            Long pid = category.getLong("parentId");
            Integer categoryLevel = category.get("areaLevel");
            if (parentId.equals(pid)) {
                List child = buildTree(list, categoryId);
                if (!categoryLevel.equals(4)) {
                    category.put("child", child);
                }
                result.add(category);
            }
        });
        return result;
    }


    /**
     * 递归构建
     *
     * @param list
     * @return
     */
    private static Map<String, List<EntityMap>> buildIndex(List<EntityMap> list) {
        Map<String, List<EntityMap>> mapZm = new LinkedHashMap<String, List<EntityMap>>();
        String[] zm = new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "Q", "R", "S", "T", "W", "X", "Y", "Z"};
        for (String s : zm) {
            mapZm.put(s, new ArrayList<EntityMap>());
        }
        for (EntityMap city : list) {
            String firstLetter = city.get("firstLetter");
            if (mapZm.containsKey(firstLetter)) {
                mapZm.get(firstLetter).add(city);
            }
        }

        return mapZm;
    }


    @Override
    public ResultBody selectIndexCity(Integer dataType, Boolean hasHot) {
        ResultBody resultBody = new ResultBody();
        List<EntityMap> allList = (List<EntityMap>) selectByLevel(2).getData();
        EntityMap result = new EntityMap();
        if (FlymeUtils.isNotEmpty(dataType) && dataType.equals(1)) {
            Map<String, List<EntityMap>> areaList = buildIndex(allList);
            List<EntityMap> result2 = new ArrayList<>();
            for (Map.Entry<String, List<EntityMap>> entry : areaList.entrySet()) {
                EntityMap map = new EntityMap();
                String mapKey = entry.getKey();
                List<EntityMap> mapValue = entry.getValue();
                map.put("idx", mapKey);
                map.put("citys", mapValue);
                result2.add(map);
            }
            result.put("cityList", result2);
        } else {
            result.put("cityList", allList);
        }
        if (hasHot) {
            List<EntityMap> hotList = selectHotList();
            result.put("hotList", hotList);
        }
        resultBody.data(result);
        return resultBody;
    }

    @Override
    public String getAreaName(Long proId, Long cityId, Long areaId) {
        String areaName = "";
        if (FlymeUtils.isNotEmpty(proId)) {
            SysArea pro = getById(proId);
            areaName += pro.getAreaName();
        }
        if (FlymeUtils.isNotEmpty(cityId)) {
            SysArea city = getById(cityId);
            areaName += city.getAreaName();
        }
        if (FlymeUtils.isNotEmpty(areaId)) {
            SysArea area = getById(areaId);
            areaName += area.getAreaName();
        }
        return areaName;
    }

    @Override
    public SysArea getDefaultSysArea() {
        CriteriaQuery<SysArea> cq = new CriteriaQuery(SysArea.class);
        cq.eq(true, "defaultArea", 1);
        return getOne(cq);
    }

    @Override
    public ResultBody afterSetState(CriteriaUpdate cq) {
        initArea(true);
        return super.afterSetState(cq);
    }

    @Override
    public ResultBody afterEdit(CriteriaUpdate cu, SysArea sysArea, EntityMap extra) {
        initArea(true);
        return super.afterEdit(cu, sysArea, extra);
    }

    @Override
    public SysArea geSysAreaByAdCode(String adCode) {
        CriteriaQuery<SysArea> cq = new CriteriaQuery(SysArea.class);
        cq.eq(true, "adCode", adCode);
        return getOne(cq);
    }
}
